﻿using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    /// <summary>
    /// 此类用以定义编辑器的折叠区。
    /// </summary>
    class CustomFoldingStrategy : AbstractFoldingStrategy
    {
        private ICSharpCode.AvalonEdit.TextEditor edit;
        /// <summary>
        /// 要应用折叠功能的编辑器。
        /// </summary>
        public ICSharpCode.AvalonEdit.TextEditor Edit { get { return this.edit; } }

        /// <summary>
        /// [构造方法]创建一个新的折叠区。
        /// </summary>
        public CustomFoldingStrategy(ICSharpCode.AvalonEdit.TextEditor edit)
        {
            this.edit = edit;
        }

        /// <summary>
        /// 为特定文档创建 NewFolding 对象集。
        /// </summary>
        public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
        {
            firstErrorOffset = -1;
            return CreateNewFoldings(document);
        }

        /// <summary>
        /// 为特定文档创建 NewFolding 对象集。
        /// </summary>
        public IEnumerable<NewFolding> CreateNewFoldings(ITextSource document)
        {
            List<NewFolding> newFoldings = new List<NewFolding>();

            List<HeaderInfo> preHeadersInfos = new List<HeaderInfo>();

            for (int i = 1; i <= edit.LineCount; i++)
            {
                var line = edit.Document.GetLineByNumber(i);

                string text = edit.Document.GetText(line.Offset, line.Length);

                if (text.StartsWith("#") == false && CustomMarkdownSupport.IsTaskLine(text) == false) continue;

                var headerText = GetHeaderOfTitleOrTaskListItem(text);
                var contentText = GetContentOfHeaderOrTaskListItem(text);

                var newHeaderInfo = new HeaderInfo()
                {
                    HeaderText = headerText,
                    ContentText = contentText,
                    Length = headerText.Length,
                    Offset = line.Offset,
                    EndOffset = line.EndOffset,
                };

                if (preHeadersInfos.Count <= 0)
                {
                    preHeadersInfos.Add(newHeaderInfo);
                    continue;
                }

                for (int j = preHeadersInfos.Count - 1; j >= 0; j--)
                {
                    if (newHeaderInfo.Length <= preHeadersInfos[j].Length)
                    {
                        var endOffset = newHeaderInfo.Offset - 2;//-2是\r\n的宽度

                        //如果在这个标题只有一行，不折叠
                        if (endOffset > preHeadersInfos[j].EndOffset)
                        {
                            var newFolding = new NewFolding(preHeadersInfos[j].Offset, newHeaderInfo.Offset - 2)
                            {
                                Name = BuildHeaderOrTaskListItemHeader(preHeadersInfos[j].HeaderText) +
                                    (string.IsNullOrEmpty(preHeadersInfos[j].ContentText) ?
                                    "... " :
                                    preHeadersInfos[j].ContentText) + " ※ ",
                            };
                            newFoldings.Add(newFolding);
                        }
                        preHeadersInfos.RemoveAt(j);
                    }
                }

                preHeadersInfos.Add(newHeaderInfo);
            }

            //到最后一行，看看要不要添加折叠块。
            if (preHeadersInfos.Count > 0)
            {
                var lastLine = this.edit.Document.GetLineByNumber(this.edit.Document.LineCount);
                if (lastLine != null)
                {
                    var lastLineText = this.edit.Document.GetText(lastLine);

                    if (lastLineText.StartsWith("#") == false && CustomMarkdownSupport.IsTaskLine(lastLineText) == false)
                    {

                        for (int j = preHeadersInfos.Count - 1; j >= 0; j--)
                        {
                            var endOffset = edit.Document.Lines.Last().Offset;//最后一行，没有\r\n，不用 - 2;

                            //如果在这个标题只有一行，不折叠
                            if (endOffset > preHeadersInfos[j].EndOffset)
                            {
                                newFoldings.Add(new NewFolding(preHeadersInfos[j].Offset, endOffset)
                                {
                                    Name = BuildHeaderOrTaskListItemHeader(preHeadersInfos[j].HeaderText) +
                                        (string.IsNullOrEmpty(preHeadersInfos[j].ContentText) ?
                                        "... " :
                                        preHeadersInfos[j].ContentText + " ※ "),
                                });
                            }
                            preHeadersInfos.RemoveAt(j);
                        }
                    }
                }
            }

            //添加试题所需要的折叠块
            Stack<int> startOffsets = new Stack<int>();
            string openingMark = "试题＞＞";
            string closingMark = "〓〓〓〓〓〓";

            for (int i = 1; i <= edit.LineCount; i++)
            {
                var line = edit.Document.GetLineByNumber(i);
                var preLine = line.PreviousLine;

                string text = edit.Document.GetText(line.Offset, line.Length).TrimStart();

                if (text.StartsWith(openingMark))
                {
                    if (preLine != null && startOffsets.Count > 0)
                    {
                        int startOffset = startOffsets.Pop();
                        // 首尾标记在同一行时不折叠。
                        if (startOffset < preLine.Offset)
                        {
                            newFoldings.Add(new NewFolding(startOffset, preLine.EndOffset)
                            {
                                Name = openingMark,
                            });
                        }
                    }

                    startOffsets.Push(line.Offset);
                }
                else if (text.StartsWith(closingMark) && startOffsets.Count > 0)
                {
                    int startOffset = startOffsets.Pop();
                    // 首尾标记在同一行时不折叠。
                    if (startOffset < line.EndOffset)
                    {
                        newFoldings.Add(new NewFolding(startOffset, line.EndOffset)
                        {
                            Name = openingMark,
                        });
                    }
                }
            }

            //添加自定义折叠块
            string startRegion = @"^[ 　]{0,3}[rｒRＲ][eｅEＥ][gｇGＧ][iｉIＩ][oｏOＯ][nｎNＮ][ 　\t]*[ｉｗｅｑiweq]?[ 　\t]*\{[ 　\t]*";
            string endRegion = @"^[ 　]{0,3}\}[ 　\t]*[rｒRＲ][eｅEＥ][gｇGＧ][iｉIＩ][oｏOＯ][nｎNＮ][ 　\t]*";

            DocumentLine preRegionLine = null;
            string regionHeaderText = null;

            for (int i = 1; i <= edit.LineCount; i++)
            {
                var line = edit.Document.GetLineByNumber(i);

                string lineText = edit.Document.GetText(line.Offset, line.Length);
                Regex regexStart = new Regex(startRegion);
                var matchStart = regexStart.Match(lineText);

                if (matchStart != null && matchStart.Success)
                {
                    regionHeaderText = lineText.Substring(matchStart.Length);
                    preRegionLine = line;
                }
                else
                {
                    Regex regexEnd = new Regex(endRegion);
                    var matchEnd = regexEnd.Match(lineText);

                    if (matchEnd != null && matchEnd.Success && preRegionLine != null)
                    {
                        newFoldings.Add(new NewFolding(preRegionLine.Offset, line.EndOffset)
                        {
                            Name = (regionHeaderText == null ? $"region{{{lineText.Substring(matchEnd.Length)}}}" : $"region{{{regionHeaderText}}}"),
                        });
                        regionHeaderText = null;
                         preRegionLine = null;
                    }
                }
            }

            newFoldings.Sort((a, b) => a.StartOffset.CompareTo(b.StartOffset));
            return newFoldings;
        }

        /// <summary>
        /// 生成标题或任务列表被折叠时显示的文本。
        /// </summary>
        /// <param name="sourceText">如果是 Header，只应传入“###”部分，不应包括后面的内容。</param>
        private string BuildHeaderOrTaskListItemHeader(string sourceText)
        {
            if (string.IsNullOrWhiteSpace(sourceText)) return "";

            if (sourceText.StartsWith("[-]") || sourceText.StartsWith("[－]")) return "[-] ";
            if (sourceText.StartsWith("[+]")) return "[+] ";
            if (sourceText.StartsWith("[%]")) return "[%] ";
            if (sourceText.StartsWith("[#]")) return "[#] ";

            var level = sourceText.Length;
            switch (level)
            {
                case 1: return "Ⅰ ※ ";
                case 2: return "Ⅱ ※ ";
                case 3: return "Ⅲ ※ ";
                case 4: return "Ⅳ ※ ";
                case 5: return "Ⅴ ※ ";
                case 6: return "Ⅵ ※ ";
                default: return "";
            }
        }

        /// <summary>
        /// 取标题或任务列表的文字部分（去除标志文本、空白字符等）。
        /// </summary>
        /// <param name="src">源文本</param>
        public string GetContentOfHeaderOrTaskListItem(string src)
        {
            if (string.IsNullOrEmpty(src)) return "";

            if (CustomMarkdownSupport.IsTaskLine(src)) return CustomMarkdownSupport.GetContentOfTaskListItem(src);

            if (src.StartsWith("#") == false) return "";

            if (src.StartsWith("######")) return src.Substring(6);
            if (src.StartsWith("#####")) return src.Substring(5);
            if (src.StartsWith("####")) return src.Substring(4);
            if (src.StartsWith("###")) return src.Substring(3);
            if (src.StartsWith("##")) return src.Substring(2);
            if (src.StartsWith("#")) return src.Substring(1);

            return "";
        }

        /// <summary>
        /// 取标题或任务列表的标志文本（不包含其它表示具体意思的文本）。
        /// </summary>
        /// <param name="src">源文本</param>
        public string GetHeaderOfTitleOrTaskListItem(string src)
        {
            if (string.IsNullOrEmpty(src)) return "";
            if (CustomMarkdownSupport.IsTaskLine(src))
            {
                return CustomMarkdownSupport.GetHeaderOfTaskListItem(src);
            }
            if (src.StartsWith("#") == false) return "";

            if (src.StartsWith("######")) return "######";
            if (src.StartsWith("#####")) return "#####";
            if (src.StartsWith("####")) return "####";
            if (src.StartsWith("###")) return "###";
            if (src.StartsWith("##")) return "##";
            if (src.StartsWith("#")) return "#";

            return "";
        }
    }

    /// <summary>
    /// 提供六级标题的折叠功能时，此类用于记录某个标题的相关位置信息。
    /// </summary>
    public class HeaderInfo
    {
        private string headerText = "...";
        public string HeaderText
        {
            get { return this.headerText; }
            set { this.headerText = value; }
        }

        private string contentText = "#";
        public string ContentText
        {
            get { return contentText; }
            set { this.contentText = value; }
        }

        private int length = 1;
        public int Length
        {
            get { return this.length; }
            set { this.length = value; }
        }

        private int offset = -1;
        public int Offset
        {
            get { return this.offset; }
            set { this.offset = value; }
        }

        private int endOffset = -1;
        public int EndOffset
        {
            get { return this.endOffset; }
            set { this.endOffset = value; }
        }

    }
}
